#include <stdio.h>
#include <quadmath.h>
#include <string.h>
#include <stdlib.h>
#include <complex.h>
#include <pthread.h>
#include <fftw3.h>

#define pi M_PIq
#define fmode FFTW_EXHAUSTIVE

typedef struct vector {
  fftwq_complex *r, *v;
} vect;

typedef struct work {
  int n;
  __float128	y0;
  fftwq_complex *Y, *Yk;
  __float128 *YY, *YYk;
  __float128 *XX, *XXk;
  __float128 *cmpYY, *cmpYYk;
  __float128 *cmpXX, *cmpXXk;
} work, *work_ptr;

typedef struct control {
  __float128 H;  // energy
  __float128 M;  // mean level
  __float128 P;  // momentum
} ctrl, *ctrl_ptr;

typedef struct io_aux {
  __float128  *XX, *YY;
} aux, *aux_ptr;

typedef struct params {
  int n, skip, t_skip, fix_flag, nthreads;
  int d, Jay, cmpn;
  __float128 g, c, dtau, tol, alfa;
  char runname[80];
  char resname[80], cmpname[80];
  ctrl current; 
  work_ptr w_ptr;
} params, *params_ptr;

//  --  ffts.c
extern void err_msg(char* str);
extern void init(int *argc, char **argv, params_ptr in, work_ptr wrk) ;
extern void hilbert(fftwq_complex *in, fftwq_complex *out);
extern void project(fftwq_complex *in, fftwq_complex *out);
extern void pproject(fftwq_complex *in, fftwq_complex *out);
extern void ffilter(fftwq_complex *in);
extern void reconstruct_surface(work_ptr in);
extern void reconstruct_potential(work_ptr in); 
extern void update_dfunc(work_ptr in);
extern void fft(fftwq_complex *in, fftwq_complex *out);
extern void ifft(fftwq_complex *in, fftwq_complex *out);

extern void fft_even(__float128 *in, __float128 *out); 
extern void ifft_even(__float128 *in, __float128 *out); 

extern void der(fftwq_complex *in, fftwq_complex *out);
extern void rhs(work_ptr in, int m);
extern void rk4(params_ptr in);

extern void generate_derivatives(work_ptr in, int m);
extern void clean_spectrum(fftwq_complex *in, fftwq_complex *out);
extern void prepare_rhs(work_ptr wrk);
extern void iterate(work_ptr wrk);
extern void iterate_cg(work_ptr wrk);
extern void iterate_cr(work_ptr wrk);

extern void prep_control_params(params_ptr in);
extern void hamiltonian(params_ptr in);
extern void mean_level(params_ptr in);
extern void momentum(params_ptr in);

//  --  prep.c
extern void writer_full(work_ptr in, char* str);
extern void init_prep(params_ptr in);
extern void write_out(fftwq_complex* in, char* str);
extern void writer_out(__float128* in, char* str, __float128 residual, __float128 y0);
extern void read_data(params_ptr in);
extern void stokes_wave(__float128 tol, params_ptr in);
extern void write_ImS(work_ptr wrk);
extern void write_Imw(work_ptr wrk);
extern void write_Rew(work_ptr wrk);
extern void init_full_write(params_ptr in, aux_ptr in2);

// -- fftws_rst.c
extern __float128 inner_product_real(__float128 *in1, __float128 *in2);
extern void init_restore(int *argc, char **argv, params_ptr in, work_ptr wrk);
extern void restore_x(params_ptr in, work_ptr wrk);
extern void ifft_odd(__float128 *in, __float128 *out);

